﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using NetManager_Server.Classes;
using System.Collections;
using System.Data.SqlClient;

namespace NetManager_Server
{
    public partial class frmManager : Form
    {
        private Socket serverSock;
        private Thread serverTh;
        private int numConnection;
        private List<Socket> lstSocket;
        private List<Client> lstClient;
        private delegate void DelegateAddClient(int no, string name, string ip, string mac);
        private delegate void DelegateRemoveClient(int position);
        private delegate void DelegateShowHistory(DataTable tbl);
        private static event EventHandler ClientDisconnectEvt;
        private function fn;

        #region htdu87 function

        private void StartServer()
        {
            IPEndPoint ipendpoint = new IPEndPoint(0, 1006);
            serverSock.Bind(ipendpoint);
            serverSock.Listen(10);
        }

        private void AcceptConnect()
        {
            while (numConnection <= 10)
            {
                //Debug.WriteLine("\r\nWaiting for connect...");
                try
                {
                    Socket sck = serverSock.Accept();
                    lstSocket.Add(sck);
                    Thread th = new Thread(() => RecData(sck));
                    SendData(sck, ObjectToByte("GIVE_ME_YOUR_INFORMATION"));
                    th.Start();
                    numConnection++;
                }
                catch { }
                
            }
            serverTh.Abort();
        }

        private void RecData(Socket sck)
        {
            string remostIP = "";
            while (sck.Connected)
            {
                byte[] byteData = ReceiveData(sck);
                object[] response = (object[])ByteToObject(byteData);
                if (response == null)
                    break;
                object[] pars = null;
                switch (response[0].ToString())
                {
                    case "GIVE_ME_YOUR_INFORMATION":
                        DelegateAddClient ac = new DelegateAddClient(AddClient);
                        pars = new object[] { numConnection, response[1], response[2], response[3] };
                        remostIP = response[2].ToString();
                        Invoke(ac, pars);
                        break;
                    case "BROWSER_HISTORY":
                        DelegateShowHistory d = new DelegateShowHistory(ShowHistory);
                        pars = new object[] { response[1] };
                        Invoke(d, pars);
                        break;
                    default:
                        break;
                }
            }
            if (ClientDisconnectEvt != null)
                ClientDisconnectEvt(remostIP, null);
            
        }

        private void SendData(Socket sck, byte[] data)
        {
            int totalSent = 0;
            int totalSize = data.Length;
            int dataLeft = totalSize;
            int sent;
            byte[] datasize = new byte[4];
            datasize = BitConverter.GetBytes(totalSize);
            sck.Send(datasize);
            while (totalSent < totalSize)
            {
                sent = sck.Send(data, totalSent, dataLeft, SocketFlags.None);
                totalSent += sent;
                dataLeft -= sent;
                Debug.WriteLine("Send: send " + totalSent + "/" + totalSize);
                Debug.WriteLine("Send: left " + dataLeft + "/" + totalSize);
            }
        }

        private byte[] ReceiveData(Socket sck)
        {
            int totalReceived = 0;
            int totalSize;
            int receive;
            byte[] totalSizeByte = new byte[4];
            sck.Receive(totalSizeByte, 0, 4, SocketFlags.None);
            totalSize = BitConverter.ToInt32(totalSizeByte, 0);
            int dataLeft = totalSize;
            byte[] data = new byte[totalSize];
            while (totalReceived < totalSize)
            {
                receive = sck.Receive(data, totalReceived, dataLeft, SocketFlags.None);
                totalReceived += receive;
                dataLeft -= receive;

                Debug.WriteLine("Receive: receive " + totalReceived + "/" + totalSize);
                Debug.WriteLine("Receive: left " + dataLeft + "/" + totalSize);
            }

            return data;
        }

        private byte[] ObjectToByte(object obj)
        {
            BinaryFormatter binary = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            binary.Serialize(ms, obj);
            return ms.ToArray();
        }

        private object ByteToObject(byte[] bytedata)
        {
            if (bytedata == null)
                return null;
            object obj = null;
            try
            {
                BinaryFormatter binary = new BinaryFormatter();
                MemoryStream ms = new MemoryStream(bytedata);
                //ms.Write(bytedata, 0, bytedata.Length);
                //ms.Seek(0, SeekOrigin.Begin);
                ms.Position = 0;
                obj = binary.Deserialize(ms);
            }
            catch(Exception ex)
            {
                Debug.WriteLine("htdu87: ByteToObject error: "+ex.Message);
            }
            return obj;
        }

        private void AddClient(int no, string name, string ip, string mac)
        {
            for (int i = 0; i < lstClient.Count; i++)
            {
                if (lstClient[i].IP == ip)
                {
                    lstClient[i].Status = "Khóa";
                    girdClient.Rows[i].Cells[3].Value = "Khóa";
                    girdClient.Rows[i].Cells[8].Value = NetManager_Server.Properties.Resources._1379489395_lock_open;
                    girdClient.Rows[i].DefaultCellStyle.BackColor = SystemColors.Window;
                    lstSocket.RemoveAt(i);
                    lstSocket.Insert(i, lstSocket[lstSocket.Count - 1]);
                    lstSocket.RemoveAt(lstSocket.Count - 1);
                    return;
                }
            }

            Client c = new Client();
            c.EndTime = DateTime.Now;
            c.IP = ip;
            c.MAC = mac;
            c.Name = name;
            c.StartTime = DateTime.Now;
            c.Status = "Khóa";

            lstClient.Add(c);
            girdClient.Rows.Add(no, name, ip, "Khóa", "", "", "", "");

            fn.addClient(mac, ip, name);
        }

        private void RemoveClient(int position)
        {
            //lstClient.RemoveAt(position);
            Client c = lstClient[position];
            if (c.Status == "Mở")
            {
                c.EndTime = DateTime.Now;
                girdClient.Rows[position].Cells["ColEndTime"].Value = c.EndTime.ToString("dd/MM/yyyy HH:mm:ss");
                girdClient.Rows[position].Cells["ColUseTime"].Value = c.UseTime;
                girdClient.Rows[position].Cells["ColMoney"].Value = c.Money;
            }

            lstClient[position].Status = "Ngắt kết nối";
            girdClient.Rows[position].Cells[3].Value = "Ngắt kết nối";
            girdClient.Rows[position].DefaultCellStyle.BackColor = Color.Red;
        }

        private void ShowHistory(DataTable tbl)
        {
            frmViewHistory frm = new frmViewHistory();
            frm.HistotyDate = tbl;
            frm.Show();
        }

        #endregion

        public frmManager()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
            ClientDisconnectEvt += new EventHandler(frmManager_ClientDisconnectEvt);
        }

        void frmManager_ClientDisconnectEvt(object sender, EventArgs e)
        {
            int i;
            bool found = false ;
            for (i = 0; i < lstClient.Count; i++)
            {
                if (sender.ToString() == lstClient[i].IP)
                {
                    found = true;
                    break;
                }
            }

            if (found)
            {
                DelegateRemoveClient rc = new DelegateRemoveClient(RemoveClient);
                object[] pars = new object[] { i };
                try { Invoke(rc, pars); }
                catch { }
            }
        }

        private void frmManager_Load(object sender, EventArgs e)
        {
            fn = new function();

            lstSocket = new List<Socket>(10);
            lstClient = new List<Client>(10);
            numConnection = 0;
            serverSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            
            StartServer();
            serverTh = new Thread(() => AcceptConnect());
            serverTh.Start();
            lblStatus.Text = "Server started";
        }

        private void frmManager_FormClosing(object sender, FormClosingEventArgs e)
        {
            serverSock.Close();
            if (serverTh != null && serverTh.IsAlive)
                serverTh.Abort();
        }

        private void girdClient_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0 || girdClient.Rows[e.RowIndex].DefaultCellStyle.BackColor == Color.Red)
                return;

            if (e.ColumnIndex == 8 && e.RowIndex >= 0)
            {
                Client c = lstClient[e.RowIndex];
                if (c.Status == "Khóa")
                {
                    c.Status = "Mở";
                    girdClient.Rows[e.RowIndex].Cells["ColStatus"].Value = c.Status;
                    c.StartTime = DateTime.Now;
                    girdClient.Rows[e.RowIndex].Cells["ColStartTime"].Value = c.StartTime.ToString("dd/MM/yyyy HH:mm:ss");
                    girdClient.Rows[e.RowIndex].Cells["ColAction"].Value = NetManager_Server.Properties.Resources._1379489407_lock;
                    girdClient.Rows[e.RowIndex].Cells["ColEndTime"].Value = String.Empty;
                    girdClient.Rows[e.RowIndex].Cells["ColUseTime"].Value = String.Empty;
                    girdClient.Rows[e.RowIndex].Cells["ColMoney"].Value = String.Empty;

                    SendData(lstSocket[e.RowIndex], ObjectToByte("UNLOCK"));
                }
                else
                {
                    c.Status = "Khóa";
                    girdClient.Rows[e.RowIndex].Cells["ColStatus"].Value = c.Status;
                    c.EndTime = DateTime.Now;
                    girdClient.Rows[e.RowIndex].Cells["ColEndTime"].Value = c.EndTime.ToString("dd/MM/yyyy HH:mm:ss");
                    girdClient.Rows[e.RowIndex].Cells["ColUseTime"].Value = c.UseTime;
                    girdClient.Rows[e.RowIndex].Cells["ColMoney"].Value = c.Money;
                    girdClient.Rows[e.RowIndex].Cells["ColAction"].Value = NetManager_Server.Properties.Resources._1379489395_lock_open;

                    SendData(lstSocket[e.RowIndex], ObjectToByte("LOCK"));

                    
                    fn.SaveSession(c.MAC, c.IP, c.StartTime, c.EndTime, c.Money);
                }
            }

            if (e.ColumnIndex == 9 && e.RowIndex >= 0)
            {
                SendData(lstSocket[e.RowIndex], ObjectToByte("SHUTDOWN"));
                girdClient.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
            }

            if (e.ColumnIndex == 10 && e.RowIndex >= 0)
            {
                SendData(lstSocket[e.RowIndex], ObjectToByte("BROWSER_HISTORY"));
            }
        }
    }
}
